<?php

namespace App\Trip\Train;

use App\Models\Common\Area\Area;
use App\Models\Common\Area\Repositories\Interfaces\AreaRepositoryInterface;
use App\Models\Train\Stations\Repositories\Interfaces\StationRepositoryInterface;
use App\Models\Train\Stations\TrainStation;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use JetBrains\PhpStorm\ArrayShape;

class TrainQueryFromToData
{
    const TYPE_CITY     = 0;
    const TYPE_DISTRICT = 1;
    const TYPE_STATION  = 2;
    private int                    $type;
    private string                 $code;
    private                        $stationRepo;
    private                        $areaRepo;
    private Area|null|TrainStation $instance;
    private string                 $name_uy = '';
    private string                 $name    = '';

    /**
     * @throws Exception
     */
    public function __construct(array $data)
    {
        $validator = Validator::make($data, [
            "type" => "required|in:0,1,2",
            "code" => "required",
        ]);

        if ($validator->fails()) {
            throw new Exception("参数错误");
        }
        $this->type = $data['type'];
        $this->code = $data['code'];

        $this->stationRepo = app(StationRepositoryInterface::class);
        $this->areaRepo    = app(AreaRepositoryInterface::class);
        $this->getInstance();

    }

    private function getInstance(): void
    {
        if (!$this->getCode()) {
            return;
        }

        $this->instance = match ($this->getType()) {
            self::TYPE_DISTRICT, self::TYPE_CITY => $this->areaRepo->findByCode($this->getCode()),
            self::TYPE_STATION                   => $this->stationRepo->findOneByCode($this->getCode()),
            default                              => null,
        };
        $this->setInstanceProperty();
    }

    public function getCode(): string
    {
        return $this->code;
    }

    public function getType(): int
    {
        return $this->type;
    }

    private function setInstanceProperty(): void
    {
        $this->name    = '';
        $this->name_uy = '';
        if ($this->instance instanceof Area) {
            $this->name    = $this->instance->getAreaName();
            $this->name_uy = $this->instance->getAreaNameUy();
        } elseif ($this->instance instanceof TrainStation) {
            $this->name    = $this->instance->getStationName();
            $this->name_uy = $this->instance->getStationNameUy();
        }
    }

    public function getName(): string
    {
        return $this->name ?: '';
    }

    public function getNameUy(): string
    {
        return $this->name_uy ?: '';
    }

    /**
     * 查询参数 转 或者站点codes
     * @return array|string[]
     */
    public function parseData2StationCodes(): array
    {
        if (self::TYPE_CITY == $this->type) {
            $station_codes = collect($this->stationRepo->listBy(['citycode' => $this->code], ['station_code']))
                ->unique('station_code')
                ->pluck('station_code')->toArray();
        } else if ($this->type == self::TYPE_DISTRICT) {
            $station_codes = collect($this->stationRepo->listBy(['adcode' => $this->code], ['station_code']))
                ->unique('station_code')
                ->pluck('station_code')->toArray();
        } else {
            $station_codes = [
                $this->code,
            ];
        }
        return $station_codes;
    }

    #[ArrayShape(['type' => "int", 'code' => "string"])]
    public function toArray(): array
    {
        return [
            'type' => $this->type,
            'code' => $this->code,
        ];
    }

    /**
     * 查询参数 转城市
     * @return array
     * @throws Exception
     */
    public function parse2City(): array
    {
        $res = [];
        if (self::TYPE_CITY == $this->type) {
            $city           = $this->instance;
            $res['code']    = $city->getAdCode();
            $res['name']    = $city->getAreaName();
            $res['name_uy'] = $city->getAreaNameUy();
        } else if ($this->type == self::TYPE_DISTRICT) {
            $strict = $this->instance;
            if (isUseCity($strict->getAreaName())) {
                $city           = $this->areaRepo->findByCode($strict->getParentCode());
                $res['code']    = $city->getAdCode();
                $res['name']    = $city->getAreaName();
                $res['name_uy'] = $city->getAreaNameUy();
            } else {
                $res['code']    = $strict->getAdCode();
                $res['name']    = $strict->getAreaName();
                $res['name_uy'] = $strict->getAreaNameUy();
            }
        } else {
            $station = $this->instance;
            if (!$station) {
                Log::error("TrainQueryFromToData:type->{$this->type}，code->{$this->code} 暂未查到车站");
            }
            $city = $station ? $this->areaRepo->findByCode($station->adcode) : null;
            if (isUseCity($city->getAreaName())) {
                $city = $this->areaRepo->findByCode($city->getParentCode());
            }
            $res['code']    = $city->getAdCode();
            $res['name']    = $city->getAreaName();
            $res['name_uy'] = $city->getAreaNameUy();
        }
        return $res;
    }
}